#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

pthread_mutex_t lock;
pthread_cond_t cond;

struct list
{
  struct list* next;
  struct list* prev;
  int data;
};

void* producer(void*);
void* consumer(void*);

struct list* head;

int main(int argc,char** argv)
{
  srand(time(NULL));
  head = malloc(sizeof(struct list));
  head->next = NULL;
  int ret;
  ret = pthread_mutex_init(&lock,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_init is fail %s\n",strerror(ret));
    exit(-1);
  }
  ret = pthread_cond_init(&cond,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_init is fail %s\n",strerror(ret));
    exit(-1);
  }
  pthread_t tid,uid;
  ret = pthread_create(&tid,NULL,producer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail %s\n",strerror(ret));
    exit(-1);
  }
  
  ret = pthread_create(&uid,NULL,consumer,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_create is fail %s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_join(tid,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_join is fail %s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_join(uid,NULL);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_join is fail %s\n",strerror(ret));
    exit(-1);
  }

  ret = pthread_mutex_destroy(&lock);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_destroy is fail %s\n",strerror(ret));
    exit(-1);
  }
  
  ret = pthread_cond_destroy(&cond);
  if(ret != 0)
  {
    fprintf(stderr,"pthread_mutex_destroy is fail %s\n",strerror(ret));
    exit(-1);
  }
  free(head);
  pthread_exit((void*)0);
}

void* producer(void* num)
{
  struct list* node;
  int ret;
  while(1)
  {
    ret = pthread_mutex_trylock(&lock);
    if(ret == 0)
    {
      node = malloc(sizeof(struct list));
      node->data = rand()%1000;
      node->next = head->next;
      head->next = node;
      printf("producer is %d\n",node->data);
      
      pthread_mutex_unlock(&lock);
      pthread_cond_signal(&cond);
      sleep(rand()%3);
    }
  }
}

void* consumer(void* num)
{
  struct list* node;
  int ret;
  while(1)
  {
    ret = pthread_mutex_trylock(&lock);
    if(ret == 0)
    {
      while(head->next == NULL)
      {
        pthread_cond_wait(&cond,&lock);
      }
      node = head->next;
      head->next = node->next;
      printf("consumer is %d\n",node->data);
      free(node);

      pthread_mutex_unlock(&lock);
      sleep(rand()%2);
    }
  }
}
